package astudy.datasource.dbf;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

public class Reader {

    private DataInputStream stream;
    private Field fields[];
    private byte nextRecord[];
    public String charsetName = "GBK";

    public Reader(String s) throws DBFException {

        stream = null;
        fields = null;
        nextRecord = null;
        try {
            init(new FileInputStream(s));
        } catch (FileNotFoundException e) {
            throw new DBFException(e);
        }
    }

    public Reader(InputStream inputstream) throws DBFException {

        stream = null;
        fields = null;
        nextRecord = null;
        init(inputstream);
    }

    private void init(InputStream inputstream) throws DBFException {

        try {
            stream = new DataInputStream(inputstream);
            int i = readHeader();
            fields = new Field[i];
            int j = 1;
            for(int k = 0; k < i; k++) {
                fields[k] = readFieldHeader();
                j += fields[k].getLength();
            }

            if(stream.read() < 1) {
				throw new DBFException("Unexpected end of file reached.");
            }
                
            nextRecord = new byte[j];
            try {
                stream.readFully(nextRecord);
            } catch (EOFException eofexception) {
                nextRecord = null;
                stream.close();
            }
        } catch (IOException ioexception) {
            throw new DBFException(ioexception);
        }
    }

    private int readHeader() throws IOException, DBFException {

        byte abyte0[] = new byte[16];
        try {
            stream.readFully(abyte0);
        } catch (EOFException eofexception) {
            throw new DBFException("Unexpected end of file reached.");
        }
        int i = abyte0[8];
        if(i < 0) {
			i += 256;
        }
        i += 256 * abyte0[9];
        i = --i / 32;
        i--;
        try {
            stream.readFully(abyte0);
        } catch (EOFException eofexception1) {
            throw new DBFException("Unexpected end of file reached.");
        }
        return i;
    }

    private Field readFieldHeader() throws IOException, DBFException {

        byte abyte0[] = new byte[16];
        try {
            stream.readFully(abyte0);
        } catch (EOFException eofexception) {
            throw new DBFException("Unexpected end of file reached.");
        }
/*
        StringBuffer stringbuffer = new StringBuffer(10);
        for(int i = 0; i < 10; i++) {
            if(abyte0[i] == 0)
                break;
            stringbuffer.append((char)abyte0[i]);
        }
*/
        //zxd modify brgin ###
        String name = new String(abyte0, 0, 10, charsetName);
        //zxd modify end ###

        char c = (char)abyte0[11];
        try {
            stream.readFully(abyte0);
        } catch (EOFException eofexception1) {
            throw new DBFException("Unexpected end of file reached.");
        }
        int j = abyte0[0];
        int k = abyte0[1];
        if(j < 0) {
			j += 256;
        }
        if(k < 0) {
			k += 256;
        }
//        return new JDBField(stringbuffer.toString(), c, j, k);
        return new Field(name, c, j, k);
    }

    public int getFieldCount() {

        return fields.length;
    }

    public Field getField(int i) {

        return fields[i];
    }

    public boolean hasNextRecord() {

        return nextRecord != null;
    }

    public Object[] nextRecord() throws DBFException,UnsupportedEncodingException {

        if(!hasNextRecord()) {
			throw new DBFException("No more records available.");
        }
            
        Object aobj[] = new Object[fields.length];
        int i = 1;
        for(int j = 0; j < aobj.length; j++) {
            int k = fields[j].getLength();
            StringBuffer stringbuffer = new StringBuffer(k);
            stringbuffer.append(new String(nextRecord, i, k, charsetName));
            aobj[j] = fields[j].parse(stringbuffer.toString());
            i += fields[j].getLength();
        }

        try {
            stream.readFully(nextRecord);
        } catch (EOFException eofexception) {
            nextRecord = null;
        } catch (IOException ioexception) {
            throw new DBFException(ioexception);
        }
        return aobj;
    }

    public static Field[] getFieldArray(String fileName) throws DBFException {

    	try {
    		String[] fieldAttribute = null;
            String line = null;
            BufferedReader br = new BufferedReader(new FileReader(fileName));
            List<Field> list = new ArrayList<Field>();
            while((line = br.readLine()) != null) {
                line = line.trim();
                if(line.length() == 0) {
					continue;
                }
                if(line.charAt(0) == '#') {
					continue;
                }
                fieldAttribute = line.split(" ");
                String name = fieldAttribute[0];
                char type = fieldAttribute[1].trim().charAt(0);
                int length = (fieldAttribute.length<3?0:Integer.parseInt(fieldAttribute[2]));
                if(type == 'd' || type == 'D') {
					length = 8;
                }
                if(type == 'l' || type == 'L' || type == 'f' || type == 'F') {
					length = 1;
                }
                int decimalCount = (fieldAttribute.length<4?0:Integer.parseInt(fieldAttribute[3]));
                list.add(new Field(name, type, length, decimalCount));
            }
            Field[] result = new Field[list.size()];
            return (Field[])(list.toArray(result));
    	} catch (FileNotFoundException e) {
    		throw new DBFException("File '" + fileName + "' is not Found!", e);
    	} catch (IOException e) {
    		throw new DBFException("Error occurs while reading File '" + fileName + "'!", e);
    	}
    }

    public Field[] getFieldArray() {

        Field[] fieldArray = new Field[getFieldCount()];
        for(int i = 0; i < getFieldCount(); i++) {
            fieldArray[i] = getField(i);
        }
        return fieldArray;
    }

}
